package org.lemon.db.store;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @since 2024-12-11 14:04
 */
public class FileManager {
    private String dir;
    private int blockSize;
    private Map<String,FileStore> openFiles;
    private Lock lock = new ReentrantLock();

    public static FileManager create(String dir,int blockSize) throws IOException{
        FileManager fm = new FileManager();
        fm.dir = dir;
        fm.blockSize = blockSize;
        fm.openFiles = new HashMap<>();
        Path dirPath = Paths.get(dir);
        if(!Files.exists(dirPath)){
            Files.createDirectory(dirPath);
        } else {
            Files.walk(dirPath).forEach(subPath -> {
                if(subPath.startsWith("temp")){
                    try {
                        Files.delete(subPath);
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
            });
        }
        return fm;
    }

    public FileStore openFile(String fileName){
        FileStore fileStore = FileStore.open(dir + fileName,"rw");
        openFiles.put(fileName,fileStore);
        return  fileStore;
    }

    public void read(BlockId blockId, Page page) {
        try {
            lock.lock();
            FileStore fileStore = openFiles.get(blockId.getFileName());
            if (fileStore == null) {
                fileStore = openFile(blockId.getFileName());
            }
            fileStore.readFully(page.buffer(), blockSize * blockId.getBlkNum(), blockSize);
        } finally {
            lock.unlock();
        }
    }

    public void write(BlockId blockId,Page page) {
        try {
            lock.lock();
            FileStore fileStore = openFiles.get(blockId.getFileName());
            if (fileStore == null) {
                fileStore = openFile(blockId.getFileName());
            }
            fileStore.writeFully(page.buffer(), blockSize * blockId.getBlkNum(), blockSize);
        } finally {
            lock.unlock();
        }
    }

    public long size(String fileName){
        File file = new File(dir + fileName);
        return  file.length()/blockSize;
    }

    public BlockId append(String fileName){
        long blockNum = size(fileName);
        BlockId blockId = new BlockId(fileName,blockNum);

        Page page = Page.create(blockSize);
        write(blockId,page);
        return blockId;
    }


    public String getDir() {
        return dir;
    }

    public void setDir(String dir) {
        this.dir = dir;
    }

    public int getBlockSize() {
        return blockSize;
    }

    public void setBlockSize(int blockSize) {
        this.blockSize = blockSize;
    }
}
